package cn.liuxb.spa;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Data
@Accessors(chain = true)
@Component
public class OrderServiceMock {
	ScheduledExecutorService notifyExecutor = Executors.newScheduledThreadPool(5);
	
	@Autowired
	SpaHandler spaHandler;

	public static enum TradeStatus {
		SUCC, FAIL, PROC
	}

	public static enum ResponseFrom {
		SYNC, ASYNC
	}

	// 按照请求参数设置返回码,决定是否模拟超时
	public PayResult pay(PayParam payParam) {
		log.info("收到支付请求:{}", payParam);
		sleep(payParam.getSyncResponseDelaySeconds());

		PayResult payResult = new PayResult().setOutTradeNo(payParam.getOutTradeNo())
				.setOrderId("Order-" + payParam.getOutTradeNo()).setTradeStatus(payParam.getExceptStatus());

		notifyExecutor.schedule(() -> notify(payResult),
				payParam.getAsyncResponseDelaySeconds() > 0 ? payParam.getAsyncResponseDelaySeconds() : 10, TimeUnit.SECONDS);

		return payResult;
	}

	private void sleep(int seconds) {
		if (seconds > 0) {
			log.info("先睡{}秒", seconds);
			try {
				TimeUnit.SECONDS.sleep(seconds);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	private void notify(PayResult payResult) {
		payResult.setRespFrom(ResponseFrom.ASYNC).setTradeStatus(TradeStatus.SUCC);
		log.info("模拟发送异步通知:" + payResult);
		spaHandler.onAsyncNotify(payResult);
	}

	@Data
	@Accessors(chain=true)
	public static class PayParam {
		private String outTradeNo;
		private int syncResponseDelaySeconds;
		private int asyncResponseDelaySeconds;
		// SUCC,FAIL,PROC
		private TradeStatus exceptStatus;
	}

	@Data
	@Accessors(chain=true)
	public static class PayResult {
		private String retCode="0000";
		private String retMsg;
		
		private String orderId;
		private String outTradeNo;
		private TradeStatus tradeStatus;
		private ResponseFrom respFrom = ResponseFrom.SYNC;
	}

}
